<template>
  <el-space wrap>
    <div style="display:flex; ">
      <el-card v-if="isVisible" class="box-card" style="width: 450px;">
        <!-- 当前选中的配音角色 -->
        <div class="avatar-text-container">
          <!-- 第一行 -->
          <div class="avatar-text-wrapper-first">
            <el-row justify="center">
              <el-col :span="24">
                <div class="avatar-text-wrapper-first">
                  <!-- 头像 -->
                  <el-avatar :src="baseUrl + currentItem.Avatarimage" />
                  <!-- 文本 -->
                  <el-text class="demonstration">{{ currentItem.DisplayName }}</el-text>
                </div>
              </el-col>
            </el-row>
          </div>
          <!-- 第二行 -->
          <div class="avatar-text-wrapper-two">
            <!-- 试听文本 -->
            <el-text>{{ currentItem.VoiceStyle.demotext }}</el-text>
          </div>
        </div>
      </el-card>
      <el-card class="box-card">
        <div class="hidden-container">
          <!-- 左边显示与影藏 -->
          <div @click="toggleVisibility" class="main-div">
            <el-icon style="font-size: 10px;" v-if="isVisible">
              <DArrowRight />
            </el-icon>
            <el-icon style="font-size: 10px;" v-if="!isVisible">
              <DArrowLeft />
            </el-icon>
          </div>
          <!-- 配音角色表   -->
          <div>
            <!-- 语音播放 -->
            <audio ref="audioPlayer" :src="audioSrc" controls class="hidden-audio"></audio>

            <!-- 发音员搜素 -->
            <el-row class="row-bg" justify="space-between">
              <el-col :span="4">
                <div style="margin-left: 0;">
                  <el-text>发音员列表</el-text>
                </div>
              </el-col>
              <el-col :span="20">
                <div class="grid-content ep-bg-purple">
                  <el-autocomplete v-model="state" :fetch-suggestions="querySearch" clearable class="inline-input w-50"
                    placeholder="请输入" @select="handleVoiceTagSelect">
                    <template #append>
                      <el-button :icon="Search" @click="search" />
                    </template>
                  </el-autocomplete>
                </div>
              </el-col>
              <!-- <el-col :span="1">
                <div class="grid-content ep-bg-purple" />
              </el-col> -->
            </el-row>
            <!-- 所属类别列表 -->
            <el-row class="row-bg" justify="space-between">
              <el-col :span="24">
                <div>
                  <el-space wrap>
                    <div v-for="item in findVoiceCatList " :key="item.link">
                      <el-button round @click="handleVoiceCatClick(item)"> {{ item.value }} </el-button>
                    </div>
                  </el-space>
                </div>
              </el-col>
            </el-row>
            <!-- 发音员列表 -->
            <el-row class="row-bg" justify="space-between">
              <el-col :span="24">
                <!-- 使用 v-for 指令来遍历每一行 -->
                <div class="row" v-for="(row, rowIndex) in groupedData" :key="rowIndex">
                  <!-- 第一行显示7个列 -->
                  <div class="first-row">
                    <div class="column">
                      <div class="cell" v-for="(item, index) in row" :key="index">
                        <!-- 单元格 -->
                        <div class="container">
                          <!-- 左边头像 -->
                          <div class="left-block" @click.stop="selectViceClick(item)">
                            <!-- 头像 -->
                            <el-avatar :src="baseUrl + item.Avatarimage" />
                            <!-- 名称 -->
                            <el-text class="demonstration">{{ item.DisplayName }}</el-text>

                          </div>
                          <!-- 右边按钮 -->
                          <div class="right-block" v-if="item.isShown">
                            <!-- 右上角五角星 -->
                            <el-icon :class="{ 'star': !item.isCollection, 'collect-star': item.isCollection }" n
                              @click="collect(item)">
                              <Star />
                            </el-icon>

                            <!-- 左下角播放按钮 -->
                            <el-button class="play-button" type="primary" :icon="CaretRight" circle
                              v-loading.fullscreen.lock="fullscreenLoading" @click="audioPlay(item)" />
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                  <!-- 第二行显示 el-descriptions -->
                  <div class="second-row" v-if="currentItem.isShown && currentItem.rowId === rowIndex">
                    <el-row class="row-bg" justify="space-between">
                      <el-col :span="6">
                        <el-text style="text-align: left;">情绪</el-text>
                      </el-col>
                      <el-col :span="17">
                        <div class="second-row-container">
                          <el-space wrap>
                            <div v-for="(VoiceStyle, id) in currentItem.VoiceStyleValue" :key="id">
                              <el-button class="second-row-button" round
                                @click.stop="handleVoiceStyleClick(VoiceStyle)">
                                <!-- <img :src="VoiceStyle.image" width="70%" height="70%"> -->
                                <el-icon v-if="VoiceStyle.image">
                                  <img :src="baseUrl + VoiceStyle.image" alt="图标" class="custom-icon" />
                                </el-icon>
                                <!-- <el-avatar :src="VoiceStyle.img"/> -->
                                {{ VoiceStyle.name }}</el-button>
                            </div>
                          </el-space>
                        </div>
                      </el-col>
                      <!-- 右边收起按钮图标 -->
                      <el-col :span="1">
                        <div style="justify-content: flex-end;">
                          <el-button style="transform: rotate(90deg);width: 20px; height: 20px;" :icon="DArrowLeft"
                            circle @click="hideDetailPanel(currentItem)" />
                        </div>
                      </el-col>
                    </el-row>
                    <!-- <el-row class="row-bg" justify="space-between">
                            <el-col :span="3">
                              <el-text>情绪强度</el-text>
                            </el-col>
                            <el-col :span="21">
                              <div class="second-row-container">
                                <div v-for="(VoiceStyle, id) in currentItem.VoiceStyleValue" :key="id">
                                  <el-button class="second-row-button" round>{{ VoiceStyle.value }}</el-button>
                                </div>
                              </div>
                            </el-col>
                          </el-row> -->
                  </div>
                </div>
              </el-col>
            </el-row>

            <!-- 语速和语调 -->
            <el-row class="row-bg" justify="space-between">
              <el-col :span="24">
                <!-- 语速 -->
                <div class="slider-demo-block">
                  <span class="demonstration">语速</span>
                  <el-slider :step="1" v-model="voiceRoleArgs.pace" :min="0" :max="12" :show-tooltip="false" show-stops
                    :marks="paceMarks" @change="changePace(voiceRoleArgs.pace)" />
                  <el-text style="margin-left: 20px;">{{ voiceRoleArgs.paceTitle }}</el-text>
                </div>

                <!-- 语调 -->
                <div class="slider-demo-block">
                  <span class="demonstration">语调</span>
                  <el-slider :step="1" v-model="voiceRoleArgs.pitch" :min="0" :max="20" :show-tooltip="false" show-stops
                    :marks="pitchMarks" @change="changePitch(voiceRoleArgs.pitch)" />
                </div>
              </el-col>
            </el-row>
          </div>
        </div>
      </el-card>
    </div>
  </el-space>
</template>

<script lang="ts">
export default {
  name: 'PronunciationButtonTable'
}
</script>

<script setup lang="ts">
// 导入Vue的响应式编程库和Element Plus的图标组件
import { onMounted, reactive, ref, computed, defineProps, defineEmits } from 'vue';
import {
  Search,
  CaretRight,
  Star,
  DArrowLeft,
  DArrowRight
} from '@element-plus/icons-vue';

// 导入axios库用于HTTP请求
import axios from 'axios';

// 导入类型定义和工具函数
import { RestaurantItem, IVoiceActor, VoiceActor, IVoiceTag, IVoiceCat, IVoiceStyle, Speech, VoiceStyle, VoiceRoleArgs, ISpeech, GetBaseURL } from '../../../composables/types';

// 导入cookie处理工具函数
import { getCookie } from '../../../composables/utils';

// 导入音频处理相关函数
import { useAudio, TextSegment, getAudioDuration, formatDuration, textToSpeech, textToSpeechBlob } from '../js/Dubbingproduction/Audiomerging';

// 接口地址
const baseUrl: string = GetBaseURL();
// 音频播放器
const audioPlayer = ref<HTMLAudioElement | null>(null);
// 音频地址
const audioSrc = ref('');
// 搜索框输入内容
const state = ref("")
//全屏显示加载中
const fullscreenLoading = ref(false);
// 播放状态,0初始化，1播放中
const audioStatus = ref(0);
// 定义事件发射函数
const emit = defineEmits([
  // 配音角色被选中时触发的事件
  'voiceActorSelected',
])
// 定义props常量，用于接收从父组件传递过来的属性
// 这里使用了defineProps函数，它是Vue 3的新特性，用于简化组件的props定义
const props = defineProps([
  // 角色id
  "voiceActorId"
])

// 下拉查询框输入事件方法
/**
 * 根据查询字符串搜索匹配的语音标签
 * @param queryString 查询字符串
 * @param cb 回调函数，用于返回搜索结果
 */
const querySearch = (queryString: string, cb: any) => {
  // 根据查询字符串过滤语音标签列表，如果查询字符串为空，则返回整个列表
  const results = queryString
    ? findVoiceTagList.value.filter(createFilter(queryString))
    : findVoiceTagList.value
  // 通过回调函数返回搜索结果
  cb(results)
}

/**
 * 创建一个过滤函数，用于在语音标签列表中筛选出匹配的项
 * @param queryString 查询字符串
 * @returns 返回一个过滤函数，该函数接受一个餐厅项，并返回一个布尔值，表示该餐厅项是否匹配查询字符串
 */
const createFilter = (queryString: string) => {
  return (restaurant: RestaurantItem) => {
    // 判断餐厅项的值是否以查询字符串开头，不区分大小写
    return (
      restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0
    )
  }
}

// 搜索框选择事件方法
function search() {
  if (state.value == "" || state.value == undefined) {
    // 重新加载配音角色列表
    loadVoiceListForTag("");
  }
  else {
    const result = voiceTagList.find(item => item.name === state.value);
    if (result) {
      // 重新加载配音角色列表
      loadVoiceListForTag(result.id.toString());
    } else {
      console.log('未找到匹配的元素');
    }
  }
}

//查询框选择事件方法
const handleVoiceTagSelect = (item: RestaurantItem) => {
  //重新加载配音角色列表
  loadVoiceListForTag(item.link);
}

//所属类别选择事件方法
const handleVoiceCatClick = (item: RestaurantItem) => {
  //重新加载配音角色列表
  loadVoiceListForCat(item.link);
}

//语音情绪选择
const handleVoiceStyleClick = (item: VoiceStyle) => {
  //当前选中的情绪
  let voiceStyleItem: IVoiceStyle;

  voiceStyleList.forEach(element => {
    if (element.id.toString() == item.id.toString()) {
      voiceStyleItem = element;
      currentItem.value.VoiceStyle = voiceStyleItem;
      currentItem.value.api_style_id = voiceStyleItem.id.toString();
    }
  });

  //调用事件，让父组件处理选中事件
  emit('voiceActorSelected', currentItem.value);
}

// 语速改变事件
function changePace(key: number) {

  audioStatus.value = 0;
  voiceRoleArgs.value.paceValue = parseFloat(paceMarks[key]);
  voiceRoleArgs.value.paceTitle = String(paceTileList[key]);
  currentItem.value.paceValue = voiceRoleArgs.value.paceValue;

  //调用事件，让父组件处理选中事件
  emit('voiceActorSelected', currentItem.value);
}

// 语调改变事件
function changePitch(key: number) {

  audioStatus.value = 0;
  voiceRoleArgs.value.pitchValue = parseFloat(pitchMarks[key]);
  currentItem.value.pitchValue = voiceRoleArgs.value.pitchValue;
  //调用事件，让父组件处理选中事件
  emit('voiceActorSelected', currentItem.value);
}

// 定义一个角色DataItem数组
let dataItems: VoiceActor[] = [];

//定义一个角色标签数组
let voiceTagList: IVoiceTag[] = [];

//定义一个角色类别列表
let voiceCatList: IVoiceCat[] = [];

//定义一个角色风格列表
let voiceStyleList: IVoiceStyle[] = [];

//发音员列表
const numbers = ref(dataItems);

// 当前选中的项
const currentItem = ref(new VoiceActor(0, '', '', ''));

//查询发音员的所属类别,查询录入框下拉数据列表
const findVoiceTagList = ref<RestaurantItem[]>([])

//查询发音员的语音分类数组
const findVoiceCatList = ref<RestaurantItem[]>([])

//语音情绪数组
const findVoiceStyleList = ref<RestaurantItem[]>([])

//语速和语调marks
type Marks = Record<number, string>

//语速数据列表
const paceMarks = reactive<Marks>({
  0: '0.5',
  1: '0.8',
  2: '0.9',
  3: '0.95',
  4: '1.0',
  5: '1.05',
  6: '1.1',
  7: '1.15',
  8: '1.2',
  9: '1.25',
  10: '1.3',
  11: '1.4',
  12: '1.5'
})

// 语速字符速率
const paceTileList = {
  0: '约3.0字/秒',
  1: '约4.4字/秒',
  2: '约4.9字/秒',
  3: '约5.2字/秒',
  4: '约5.5字/秒',
  5: '约5.7字/秒',
  6: '约6.0字/秒',
  7: '约6.3字/秒',
  8: '约6.5字/秒',
  9: '约6.8字/秒',
  10: '约7.1字/秒',
  11: '约7.1字/秒',
  12: '约8.2字/秒',
}

//语调数据列表
const pitchMarks = reactive<Marks>({
  0: '-10',
  1: '-9',
  2: '-8',
  3: '-7',
  4: '-6',
  5: '-5',
  6: '-4',
  7: '-3',
  8: '-2',
  9: '-1',
  10: '0',
  11: '1',
  12: '2',
  13: '3',
  14: '4',
  15: '5',
  16: '6',
  17: '7',
  18: '8',
  19: '9',
  20: '10',
})

//当前的语速和语调和音量参数类
const voiceRoleArgs = ref(new VoiceRoleArgs(3, parseFloat(paceMarks[3]), 10, parseFloat(pitchMarks[10]), 1, "约5.2字/秒"))


/**
 * 根据Tag加载语音角色列表(自已调制版)
 * 此函数旨在通过API调用，获取与特定标签ID相关的语音演员列表
 * 当标签ID为空或未定义时，加载所有语音演员
 * @param api_tag_ids {string} - 标签ID，用于过滤语音演员列表
 * @returns {void} - 无返回值，但会更新全局变量dataItems和numbers.value
 */
function loadVoiceListForTag(api_tag_ids: string): void {
  //其实打开时已加载了所有配间角色了，这里可以不用再加载了，只是最新角色的数据取不到
  axios.get(baseUrl + '/api/tts/tts/getVoice', {
    headers: {
      'Content-Type': 'application/json',
    }
  })
    .then(response => {
      // 处理响应数据
      const data = response.data as VoiceActor[];
      dataItems = [];
      let tempList: string[] = [];

      // 根据提供的api_tag_ids参数判断加载全部还是特定标签的角色
      if (api_tag_ids == "" || api_tag_ids == undefined) {
        //是空，加载全部角色
        for (let i = 0; i < data.length; i++) {
          dataItems.push(data[i]);
        }
      }
      else {
        //根据选择中的数据码加载角色
        for (let i = 0; i < data.length; i++) {
          tempList = data[i].api_tag_ids.split(",");
          if (tempList.includes(api_tag_ids)) {
            dataItems.push(data[i]);
          }
        }
      }
      numbers.value = dataItems;

      //默认选中第一个
      if (dataItems.length > 0) {
        selectViceClick(dataItems[0]);
      }
    })
    .catch(error => {
      // 处理错误
      console.log(error)
    });
}


/**
 * 根据分类加载语音角色列表(自已调制版)
 * @param api_cat_id - 类别ID，用于筛选语音角色如果为空或未定义，则加载所有角色
 */
function loadVoiceListForCat(api_cat_id: string): void {
  // 发起HTTP GET请求以获取语音角色数据
  axios.get(baseUrl + '/api/tts/tts/getVoice', {
    headers: {
      'Content-Type': 'application/json',
    }
  })
    .then(response => {
      // 处理响应数据
      const data = response.data as VoiceActor[];
      dataItems = [];
      let tempList: string[] = [];

      // 检查api_cat_id是否为空或未定义，以决定加载全部角色还是根据类别ID筛选
      if (api_cat_id == "" || api_cat_id == undefined) {
        //是空，加载全部角色
        for (let i = 0; i < data.length; i++) {
          dataItems.push(data[i]);
        }
      }
      else {
        //根据选择中的数据码加载角色
        for (let i = 0; i < data.length; i++) {
          tempList = data[i].api_tag_ids.split(",");
          if (tempList.includes(api_cat_id)) {
            dataItems.push(data[i]);
          }
        }
      }
      // 更新角色列表
      numbers.value = dataItems;
      //默认选中第一个
      if (dataItems.length > 0) {
        selectViceClick(dataItems[0]);
      }
    })
    .catch(error => {
      // 处理错误
      console.log(error)
    });
}

/**
 * 加载声音演员列表
 * 该函数通过发送GET请求来获取声音演员列表数据，并处理相关逻辑
 */
function loadVoiceList(): void {
  // 发起GET请求，获取声音演员列表数据
  // 从声音广场传入的配音角色Id
  let voiceActorId: number = props.voiceActorId;
  // 初始化选中的声音演员项为undefined
  let selectItem: VoiceActor | undefined = undefined;

  // 发送GET请求获取声音演员数据
  axios.get(baseUrl + '/api/tts/tts/getVoice', {
    headers: {
      'Content-Type': 'application/json',
    }
  })
    .then(response => {
      // 处理响应数据
      dataItems = response.data as VoiceActor[];

      //设置默认的当前选中项
      Object.assign(currentItem.value, dataItems[0]);

      //处理头像地址,加上基地址
      for (let i = 0; i < dataItems.length; i++) {
        // dataItems[i].Avatarimage = baseUrl + dataItems[i].Avatarimage;
        //寻找匹配的选中项
        if (voiceActorId == dataItems[i].id) {
          selectItem = dataItems[i];
        }
      }
      //更新列表数据
      numbers.value = dataItems;

      //如果没有选中项且数据列表不为空，则选中第一个
      if (selectItem == undefined) {
        if (dataItems.length > 0) {
          selectItem = dataItems[0];
        }
      }

      //默认选中第一个
      if (selectItem != undefined) {
        selectViceClick(selectItem);
      }
    })
    .catch(error => {
      // 处理错误
      console.log(error)
    });
}

/**
 * 加载语音Tag列表
 * 该函数通过发送GET请求来获取语音标签数据，并将其转换为RestaurantItem对象数组返回
 * 使用Promise来处理异步操作，确保数据加载完成后才进行后续处理
 * 
 * @returns {Promise<RestaurantItem[]>} 返回一个Promise，解析为RestaurantItem对象数组
 */
function loadVoiceTagList(): Promise<RestaurantItem[]> {
  // 初始化一个空的RestaurantItem数组，用于存储转换后的语音标签数据
  let findVoiceTagList: RestaurantItem[] = [];
  // 初始化一个空的字符串数组，用于临时存储已处理的标签名称，以避免重复
  let tempList: string[] = [];

  // 返回一个新的Promise对象，处理异步请求
  return new Promise<RestaurantItem[]>((resolve, reject) => {
    // 发送GET请求到指定的API端点，获取语音标签数据
    axios.get(baseUrl + '/api/tts/tts/getVoiceTag', {
      headers: {
        'Content-Type': 'application/json',
      }
    })
      .then(response => {
        // 将响应数据转换为IVoiceTag数组类型
        const data = response.data as IVoiceTag[];
        // 遍历响应数据，将每个语音标签转换为RestaurantItem对象
        for (let i = 0; i < data.length; i++) {
          // 检查tempList中是否已存在当前标签名称，以去重
          if (!tempList.includes(data[i].name)) {
            // 如果不存在，将标签名称添加到tempList中，并创建新的RestaurantItem对象添加到findVoiceTagList中
            tempList.push(data[i].name);
            findVoiceTagList.push(new RestaurantItem(data[i].name, data[i].id.toString()));
          }
        }
        // 成功解析Promise，返回转换后的RestaurantItem对象数组
        resolve(findVoiceTagList);
      })
      .catch(error => {
        // 如果发生错误，拒绝Promise，并传递错误信息
        reject(error);
      });
  });
}


/**
 * 加载语音情绪列表
 * 该函数通过发送GET请求来获取语音分类数据，并将其转换为RestaurantItem对象数组返回
 * 
 * @returns {Promise<RestaurantItem[]>} 返回一个Promise，解析为RestaurantItem对象数组
 */
function loadVoiceCatList(): Promise<RestaurantItem[]> {
  // 初始化一个空数组，用于存储查找的语音分类项
  let findVoiceCatList: RestaurantItem[] = [];
  // 初始化一个空数组，用于临时存储已处理的分类名称，以避免重复
  let tempList: string[] = [];

  // 返回一个新的Promise对象，用于处理异步请求
  return new Promise<RestaurantItem[]>((resolve, reject) => {
    // 发送GET请求到指定的API端点
    axios.get(baseUrl + '/api/tts/tts/getVoiceCat', {
      headers: {
        'Content-Type': 'application/json',
      }
    })
      .then(response => {
        // 将响应数据转换为IVoiceCat类型数组
        voiceCatList = response.data as IVoiceCat[];

        // 遍历获取到的语音分类列表
        for (let i = 0; i < voiceCatList.length; i++) {
          // 检查临时列表中是否已存在当前分类的名称
          if (!tempList.includes(voiceCatList[i].name)) {
            // 如果不存在，则添加到临时列表和查找列表中
            tempList.push(voiceCatList[i].name);
            findVoiceCatList.push(new RestaurantItem(voiceCatList[i].name, voiceCatList[i].id.toString()));
          }
        }
        // 解析Promise，返回查找的语音分类列表
        resolve(findVoiceCatList);
      })
      .catch(error => {
        // 如果发生错误，通过Promise的reject方法传递错误
        reject(error);
      });
  });
}

/**
 * 异步加载语音情绪列表
 * 此函数通过发送GET请求获取语音风格数据，并对其进行处理，去除重复的英语名称，最终返回一个Promise对象，包含处理后的语音风格列表
 * @returns {Promise<RestaurantItem[]>} 返回一个Promise对象，包含处理后的语音风格列表
 */
function loadVoiceStyleList(): Promise<RestaurantItem[]> {
  // 初始化一个空的语音风格列表
  var findVoiceStyleList: RestaurantItem[] = [];
  // 初始化一个空的临时列表，用于去重
  let tempList: string[] = [];

  // 返回一个Promise对象，用于异步获取语音风格列表
  return new Promise<RestaurantItem[]>((resolve, reject) => {
    // 发送GET请求获取语音风格数据
    axios.get(baseUrl + '/api/tts/tts/getVoiceStyle', {
      headers: {
        'Content-Type': 'application/json',
      }
    })
      .then(response => {
        // 将响应数据解析为IVoiceStyle类型数组
        voiceStyleList = response.data as IVoiceStyle[];

        // 遍历语音风格列表，过滤重复的英语名称，并构建findVoiceStyleList列表
        for (let i = 0; i < voiceStyleList.length; i++) {
          // 如果临时列表中不包含当前语音风格的英语名称，则将其添加到临时列表和findVoiceStyleList中
          if (!tempList.includes(voiceStyleList[i].en_name)) {
            tempList.push(voiceStyleList[i].en_name);
            // 构建RestaurantItem对象，使用语音风格的名称和ID
            findVoiceStyleList.push(new RestaurantItem(voiceStyleList[i].name, voiceStyleList[i].id.toString()));
          }
        }
        // 成功完成Promise，返回findVoiceStyleList列表
        resolve(findVoiceStyleList);
      })
      .catch(error => {
        // 如果发生错误，通过Promise的reject方法传递错误
        reject(error);
      });
  });
}


// 选中语音角色
function selectViceClick(item: VoiceActor): void {
  // 初始化显示状态和情绪列表
  let isshow = false;
  let tempList: string[] = [];

  try {

    //调用事件，让父组件处理选中事件
    emit('voiceActorSelected', item);

    // 介绍框显示
    isVisible.value = true;
    // 强制显示当前选中的项
    isshow = true;
    // 隐藏所有项
    hideAll(item);
    // 显示当前项
    item.isShown = isshow;

    // 复制选中项到当前项
    Object.assign(currentItem.value, item);

    // 初始化语音情绪相关变量
    let voiceStyleItem: IVoiceStyle;

    // 清空音频源
    audioSrc.value = "";

    // 获取当前项的情绪列表并分割成数组
    tempList = currentItem.value.api_style_ids.split(",");

    // 清空当前项的情绪值数组
    for (let i: number = currentItem.value.VoiceStyleValue.length - 1; i >= 0; i--) {
      currentItem.value.VoiceStyleValue.pop();
    }

    // 设置当前选中的情绪
    voiceStyleList.forEach(element => {
      if (element.id.toString() == currentItem.value.api_style_id) {
        voiceStyleItem = element;
        currentItem.value.VoiceStyle = voiceStyleItem;
      }
    });

    // 添加找到的情绪到当前项的情绪值数组
    for (let i: number = 0; i < tempList.length; i++) {
      voiceStyleList.forEach(element => {
        if (element.id.toString() == tempList[i]) {
          voiceStyleItem = element;

          // 设置第一个情绪为默认选中
          if (i == 0) {
            currentItem.value.VoiceStyle = voiceStyleItem;
          }
          currentItem.value.VoiceStyleValue.push(voiceStyleItem);
        }
      });
    }
  }
  catch (e) {
    // 打印错误信息
    console.log(e);
  }
}

// 设置所有按钮不显示状态的方法
function hideAll(item: VoiceActor): void {
  for (let i = 0; i < numbers.value.length; i++) {
    numbers.value[i].isShown = false;
  }
}

// 收起详情面板
function hideDetailPanel(item: VoiceActor): void {
  item.isShown = false;
  hideAll(item);
}


// 收藏按钮事件处理
function collect(item: IVoiceActor): void {
  item.isCollection = !item.isCollection;
  console.log("收藏collect", item);
}

/**
 * 播放音频函数
 * @param item VoiceActor类型的项，表示语音演员的信息
 */
function audioPlay(item: VoiceActor): void {
  // 初始化音频URL
  let audioUrl: string = "";
  // 创建ISpeech类型的speechArgs对象
  let speechArgs: ISpeech = new Speech();

  // 创建音频对象
  if (!currentItem.value.VoiceStyle) {
    // 如果当前项没有语音样式，则直接返回
    return;
  }

  // 检查是否有正在播放的音频
  if (audioPlayer.value) {
    if (audioSrc.value && audioStatus.value == 1) {
      // 如果有音频在播放，根据音频播放状态决定是暂停还是继续播放
      if (audioPlayer.value.paused) {
        // 如果音频暂停，则继续播放
        playAudio();
      } else {
        // 如果音频正在播放，则暂停播放
        pauseAudio();
      }

      // 返回，以避免执行后续代码
      return;
    }
  }

  pauseAudio();
  audioStatus.value = 1;
  // 设置语音合成参数
  speechArgs.text = currentItem.value.VoiceStyle.demotext; // 设置合成文本
  speechArgs.voiceName = currentItem.value.ShortName; // 设置发音人名称
  speechArgs.rate = voiceRoleArgs.value.paceValue.toString(); // 设置语速
  speechArgs.volume = '+10.00%'; // 设置音量
  speechArgs.pitch = (voiceRoleArgs.value.pitchValue * 100).toString() + "%"; // 设置音调
  speechArgs.style = currentItem.value.VoiceStyle.en_name;  // 设置讲话风格
  speechArgs.role = ''; // 设置讲话角色扮演
  speechArgs.styleDegree = currentItem.value.styleDegree.toString();  // 设置讲话风格的强度
  speechArgs.breakTime = '250';  // 设置停顿时间

  // 打印speechArgs对象以供调试
  console.log("speechArgs", speechArgs);

  //显示全屏遮罩
  fullscreenLoading.value = true;
  // 调用语音合成方法
  textToSpeechBlob(speechArgs).then(result => {
    if (result) {
      //关闭全屏遮罩
      fullscreenLoading.value = false;
      // 如果合成成功，更新音频URL并开始播放
      audioUrl = result;
      audioSrc.value = audioUrl;
      // 开始加载并播放音频
      loadPlayAudio();
    }
  }).catch(error => {
    //关闭全屏遮罩
    fullscreenLoading.value = false;
    // 错误处理
  });
}

// 计算属性，用于将数据分组
const groupedData = computed(() => {

  let result = [];
  let subresult = [];
  let xh: number = 0;


  for (let i = 0; i < numbers.value.length; i++) {
    if ((i + 1) % 7 === 1) {
      //每行显示7个
      subresult = new Array();
      result.push(subresult);
      xh = Math.floor(i / 5);
    }
    numbers.value[i].rowId = xh;
    subresult.push(numbers.value[i]);
  }
  return result;
});

// 初始化 audioPlayer
const initializeAudioPlayer = () => {
  if (audioPlayer.value) {
    audioPlayer.value.addEventListener('ended', () => {
      URL.revokeObjectURL(audioPlayer.value.src);
    });
  }
};

// 加载并播放音频
const loadPlayAudio = () => {
  if (audioPlayer.value) {
    // 确保音频已加载
    audioPlayer.value.load(); // 尝试加载音频

    // 监听 canplay 事件，确保音频加载完成后播放
    audioPlayer.value.addEventListener('canplay', () => {
      audioPlayer.value.play().catch(error => {
        console.error('语音播放出错:', error);
        handleAudioError(error);
      });
    }
    );
  }
};

// 播放音频
const playAudio = () => {
  if (audioPlayer.value) {
    audioPlayer.value.play();
  }
};

/**
 * 暂停音频播放
 * 当audioPlayer存在时，调用其pause方法暂停播放
 */
const pauseAudio = () => {
  if (audioPlayer.value) {
    audioPlayer.value.pause();
  }
};

/**
 * 停止音频播放并重置播放位置
 * 当audioPlayer存在时，不仅暂停播放，还将播放位置重置到开头
 */
const stopAudio = () => {
  if (audioPlayer.value) {
    audioPlayer.value.pause();
    audioPlayer.value.currentTime = 0;
  }
};


// 处理音频错误
const handleAudioError = (error) => {
  if (error.name === 'NotAllowedError') {
    console.error('用户拒绝了音频播放权限');
  } else if (error.name === 'NotReadableError') {
    console.error('音频文件无法读取');
  } else if (error.name === 'NetworkError') {
    console.error('网络错误导致无法加载音频文件');
  } else if (error.name === 'AbortError') {
    console.error('音频播放被取消');
  } else {
    console.error('未知错误：', error);
  }
};

// 定义一个响应式变量来控制目标 div 的显示与隐藏
const isVisible = ref(false);

// 点击事件处理函数
const toggleVisibility = () => {
  isVisible.value = !isVisible.value;
};

// 刷新父组件的方法
function refreshParent() {
  const user = getCookie('nightMode');
  if (user === '') {
    targetDiv.value.className = "light";
  } else {
    targetDiv.value.className = user;
  }
}

// 定义暴露给父组件的方法和属性
defineExpose({
  // 暴露给父组件的配音角色
  currentItem,
  //刷新主题
  refreshParent
});

//绑定到DOM后执行的代码
onMounted(() => {

  // 加载Tag查询框
  loadVoiceTagList()
    .then(items => {
      findVoiceTagList.value = items
    })
    .catch(error => {
      console.error(error);
    });

  //加载语音分类列表
  loadVoiceCatList()
    .then(items => {
      findVoiceCatList.value = items
    })
    .catch(error => {
      console.error(error);
    });


  //加载语音情绪列表
  loadVoiceStyleList()
    .then(items => {
      findVoiceStyleList.value = items;

      //取到配音角色列表
      loadVoiceList();
    })
    .catch(error => {
      console.error(error);
    });

  //初始化音频播放器
  initializeAudioPlayer();

})

</script>


<style scoped>
.hidden-container {
  display: flex;
  flex-direction: row;
  gap: 20px;
}

.hidden-audio {
  display: none;
  /* 隐藏音频元素 */
}

.custom-icon {
  width: 16px;
  /* 图标的宽度 */
  height: 16px;
  /* 图标的高度 */
  margin-right: 5px;
  /* 图标与文字之间的间距 */
  vertical-align: middle;
  /* 垂直居中对齐 */
}

.avatar-text-container {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* 水平居中对齐 */
  align-items: center;
  /* 垂直居中对齐 */
  height: 100%;
  /* 确保容器高度 */
}

.avatar-text-wrapper-first {
  display: flex;
  align-items: center;
  /* 水平居中对齐 */
}

.avatar-text-wrapper-first {
  display: flex;
  align-items: center;
  height: 80px;
  /* 水平居中对齐 */
}

.avatar-text-wrapper-two {
  display: flex;
  align-items: center;
  height: 100%;
  /* 水平居中对齐 */
}

.demonstration {
  text-align: center;
  /* 文本居中对齐 */
}

.row {
  display: flex;
  flex-direction: column;
  gap: 20px;
  /* 增加上下间距 */
}

.first-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.second-row {
  display: flex;
  justify-content: left;
  align-items: center;
  flex-wrap: wrap;
}

.column {
  display: flex;
  flex-wrap: nowrap;
  flex-direction: row;
  gap: 10px;
}

.cell {
  display: inline-block;
  border: 1px solid #ccc;
  cursor: pointer;
  border-radius: 8px;
  width: 100%;
  /* 示例宽度 */
}

/* 配音角色数据div */
.container {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  height: 60px;
  width: auto;
  padding: 10px 0px;
}

/* 头像和名称文本 */
.left-block {
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
  display: inline-block;
  box-sizing: border-box;
  margin: 10px 10px 10px 10px;
  width: auto;
}

/* 头像 */
.container .el-image {
  width: 30px;
  /* 图片宽度 */
  height: 30px;
  /* 图片高度 */
  border-radius: 50%;
  /* 设置为圆形 */
}

/* 头像下面的文本 */
.container .demonstration {
  display: block;
  color: var(--el-text-color-secondary);
  white-space: nowrap;
  /* 禁止文本换行 */
}

/* 右边两按钮 */
.right-block {
  display: flex;
  /* 使 right-block 成为 flex 容器 */
  flex-direction: column;
  /* 子元素按列排列 */
  justify-content: space-between;
  /* 垂直方向两端对齐 */
  align-items: flex-start;
  /* 水平方向左对齐 */
  height: 60px;
  width: 40px;
}

/* 右上角五角星 */
.right-block .star {
  display: block;
  color: var(--el-text-color-secondary);
  width: 20px;
  height: 20px;
  margin-left: auto;
  margin-bottom: auto;
  margin-right: 2px;
  margin-top: 2px;

  transition: background-color 0.3s;
  /* 平滑过渡效果 */
}

/* 右上角五角星 */
.right-block .collect-star {
  display: block;
  color: var(--el-text-color-secondary);
  /* background-color: aquamarine; */
  width: 20px;
  height: 20px;
  margin-left: auto;
  margin-bottom: auto;
  margin-right: 2px;
  margin-top: 2px;

  transition: background-color 0.3s;
  /* 平滑过渡效果 */
}

.right-block .star:hover {
  cursor: pointer;
  /* 鼠标指针变为手形 */
  color: red;
  /* 鼠标移入时的背景色 */
}

/* 播放按钮 */
.right-block .play-button {
  margin-right: auto;
  margin-top: auto;
  margin: 0 0 10px 0;
  width: 20px;
  height: 20px;
}

/* 语速 */
.slider-demo-block {
  display: flex;
  flex-direction: row;
  align-items: center;
  margin-bottom: 20px;
}

.slider-demo-block .el-slider {
  margin-top: 0;
  margin-left: 20px;
}

.slider-demo-block .demonstration {
  color: var(--el-text-color-secondary);
  text-overflow: ellipsis;
  white-space: nowrap;
  margin-bottom: 0;
}

.slider-demo-block .demonstration+.el-slider {
  flex: 0 0 70%;
}

/* 第二行展示面板 */
.second-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.second-row-button {
  padding: 10px 20px;
}

.second-row-container {
  display: flex;
  flex-direction: row;
  box-sizing: border-box;
}

.second-row-button:hover {
  background-color: #0056b3;
}

/* 特效控制样式 */
.main-div {
  position: relative;
  border: 1px solid transparent;
  width: 10px;
  cursor: pointer;
  display: flex;
  align-items: center;
  /* 垂直居中 */
  justify-content: flex-start;
  /* 水平居左 */
}
</style>